DynamoDBテーブルの attribute_exists() が最上位のAttribute以外でも使えるか試してみる
DynamoDBテーブルのアイテムを追加したり更新するとき、条件として下記をよく利用します。
- attribute_not_exists()
- attribute_exists()
ふと思いました。「たとえば、dict(map)の深い階層のAttributeに対しても使えるのだろうか?」と。試してみました。
おすすめの方
- DynamoDBの条件指定について知りたい方
- DynamoDBの条件式の組み込み関数について知りたい方
適当なDynamoDBテーブルを用意する
既存の適当なDynamoDBテーブルを利用します。
まずは、最上位のAttributeで試す
import boto3 dynamodb = boto3.resource("dynamodb") table = dynamodb.Table("boto3-test") def main(): print("--- init ---") table.put_item( Item={"todoId": "t0001", "title": "あめちゃんを買う", "deadline": "2023-09-15"} ) # title が無いなら、追加したい print("--- expected: ConditionalCheckFailedException ---") try: table.update_item( Key={"todoId": "t0001"}, UpdateExpression="set #title = :title", ExpressionAttributeNames={"#title": "title"}, ExpressionAttributeValues={":title": "アイスを買う"}, ConditionExpression="attribute_not_exists(title)", ) except Exception as e: print(e) # note があるなら、更新したい print("--- expected: ConditionalCheckFailedException ---") try: table.update_item( Key={"todoId": "t0001"}, UpdateExpression="set #note = :note", ExpressionAttributeNames={"#note": "note"}, ExpressionAttributeValues={":note": "予算は300円"}, ConditionExpression="attribute_exists(note)", ) except Exception as e: print(e) if __name__ == "__main__": main()
これは、期待通りの動作でした。
--- init --- --- expected: ConditionalCheckFailedException --- An error occurred (ConditionalCheckFailedException) when calling the UpdateItem operation: The conditional request failed --- expected: ConditionalCheckFailedException --- An error occurred (ConditionalCheckFailedException) when calling the UpdateItem operation: The conditional request failed
深い階層にあるAttributeで試す
次の2つに対して、attribute_not_exists()
とattribute_exists()
を試してみます。
- detail.color.blue
- detail.color.white
import boto3 dynamodb = boto3.resource("dynamodb") table = dynamodb.Table("boto3-test") def main(): print("--- init ---") table.put_item( Item={ "todoId": "t0001", "detail": { "title": "あめちゃんを買う", "color": {"red": "#ff0000", "green": "#00ff00", "blue": "#0000ff"}, "deadline": "2023-09-15", }, } ) # blue が無いなら、 bule をこっそり追加する print("--- expected: ConditionalCheckFailedException ---") try: table.update_item( Key={"todoId": "t0001"}, UpdateExpression="set #detail.#color.#blue = :black", ExpressionAttributeNames={ "#detail": "detail", "#color": "color", "#blue": "blue", }, ExpressionAttributeValues={":black": "#000000"}, ConditionExpression="attribute_not_exists(#detail.#color.#blue)", ) except Exception as e: print(e) # white が有るなら、 white をこっそり変える print("--- expected: ConditionalCheckFailedException ---") try: table.update_item( Key={"todoId": "t0001"}, UpdateExpression="set #detail.#color.#white = :black", ExpressionAttributeNames={ "#detail": "detail", "#color": "color", "#white": "white", }, ExpressionAttributeValues={":black": "#000000"}, ConditionExpression="attribute_exists(#detail.#color.#white)", ) except Exception as e: print(e) if __name__ == "__main__": main()
「ConditionalCheckFailedException」が発生しました。
--- init --- --- expected: ConditionalCheckFailedException --- An error occurred (ConditionalCheckFailedException) when calling the UpdateItem operation: The conditional request failed --- expected: ConditionalCheckFailedException --- An error occurred (ConditionalCheckFailedException) when calling the UpdateItem operation: The conditional request failed
さいごに
深い階層でも問題なく利用できました。これは嬉しいですね。 複雑なデータの深いAttributeを条件付きで更新したい場合などでもバッチリです。 参考になれば幸いです。